/**
 * @author notifyer
 * @email ls5231#gmail.com
 */
package org.openjava.jsonbuilder;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Date;

import org.openjava.utils.ArrayUtils;
import org.openjava.utils.ReflectionUtils;
import org.openjava.utils.RegExpUtils;
import org.openjava.utils.StringUtils;






public class JSONBuilder {
	private  StringBuffer buffer  = new StringBuffer();
	private  boolean array = false;
	private String quote = "\"";
	
	/**
	 * 
	 * @param array 是否是生成数组,默认为false
	 */
	public  void setArray() {
		array = true;
		
	}
	
	public  void setObj(){
		array = false;
		
	}
	/**
	 * 
	 * @param toArray if to generate array json
	 */
	 public   JSONBuilder(boolean toArray) {
		array = toArray;
		
		if(array){
			buffer.append("[");
		}else{
			buffer.append("{");
		}
	}
	 
	 /**
	  * 
	  * @param toArray if to generate array json
	  * @param quote  
	  */
	 public   JSONBuilder(boolean toArray,String quote) {
			array = toArray;
			this.quote = quote;
			if(array){
				buffer.append("[");
			}else{
				buffer.append("{");
			}
		}
	 
	 /**
	  * 
	  * @param quote
	  */
	 public JSONBuilder(String quote){
		 this.quote = quote;
		 buffer.append("{");
	 }
	 public JSONBuilder() {
		 buffer.append("{");
	}
	
	 /**
	  * 
	  * @param obj
	  * @throws Exception
	  */
	public  void  putElement(Object obj)  {
		if(obj.getClass().isArray()){
			try {
				buffer.append(fromObject(obj,quote));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}else{
			try {
				buffer.append(fromObject(obj,quote));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		buffer.append(",");
	}
	
	/**
	 * 
	 * @param key
	 * @param obj
	 */
	public   void  putElement(String key,Object obj)  {
		key = key.replaceAll("\"", "\\\\\"");
		if(obj.getClass().isArray()){
			buffer.append(quote).append(key).append(quote).append(":").append(fromArray(obj,quote));
		}else{
			if(ReflectionUtils.isJSONMinObj(obj)){
				buffer.append(quote).append(key).append(quote).append(":").append(meanObj(obj,quote));
			}
			else
			buffer.append(quote).append(key).append(quote).append(":").append(fromObject(obj,quote));
		}
		buffer.append(",");
	}
	
	private static Object meanObj(Object obj,String quote){
		if(obj instanceof String){
			return quote + obj + quote;
		}else return obj;
	}
	
	/**
	 * generate the json string
	 */
	public  String buildJSON(){
		if(buffer.length() == 0){
			if(array){
				buffer.append("[");
			}else{
				buffer.append("{");
			}
		}
		if(array){
			buffer.deleteCharAt(buffer.length() -1).append("]");
		}else{
			buffer.deleteCharAt(buffer.length() -1).append("}");
		}
	 	if(this.quote.equals("'"))
	 	return RegExpUtils.replaceQuotation(buffer.toString());
		return buffer.toString();
	}
	
	/**
	 * @param obj the object from which the json-string generate  
	 * 
	 */
	public static String fromObject(Object obj) {
		try {
			return fromObject(obj, "\"");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 
	 * @param obj the object from which the json-string generate
	 * @param buffer the buffer which store the json string
	 * @param quote
	 * @return
	 */
	private static String fromObject(Object obj,StringBuffer buffer,String quote) {
		if(obj == null){
			return "null";
		}
		if(obj.getClass().isArray()){
			 new Exception("argument is a array, use fromArray instead").printStackTrace();
			 return null;
		}
		if(obj.getClass().getName().equals("java.lang.Object")){
			return obj.toString();
		}
		if(ReflectionUtils.isJSONMinObj(obj)){
			return obj.toString();
		}
		Method[] methods = obj.getClass().getDeclaredMethods();
		buffer.append("{");
		String name = null;
		for(int i=0, j = methods.length;i < j;i ++){
			if((name = methods[i].getName()).indexOf("get") == 0 
					&& methods[i].getParameterTypes().length == 0
					&& methods[i].getModifiers() == Modifier.PUBLIC
			){
				Object object = ReflectionUtils.invokeMethod(obj, methods[i]);
				String propery = StringUtils.unCapitalize(name.substring(3));
				if(object == null){
					buffer.append(quote).append(propery).append(quote).append(":").append("null").append(",");
				}
				else if(object.getClass().isArray()){
					buffer.append(quote).append(propery).append(quote).append(":").append(fromArray(object,quote)).append(",");
				}else{
					if(ReflectionUtils.isJSONMinObj(object)){
						if(object instanceof String){
							object = quote + ((String)object).replaceAll("\\\"", "\\\\\"") + quote;
							
						}
						buffer.append(quote).append(propery).append(quote).append(":").append(object).append(",");
					}else{
						buffer.append(quote).append(propery).append(quote).append(":");
						fromObject(object,buffer,quote);
						buffer.append(",");
					}
				}
			}
		}
		return buffer.deleteCharAt(buffer.length() -1).append("}").toString();
	}
	
	/**
	 * 
	 * @param obj the object from which the json-string generate
	 * @param quote
	 * @return
	 */
	public static String fromObject(Object obj,String quote) {
		StringBuffer buf = new StringBuffer();
		return fromObject(obj,buf,quote);
	}
	
	/**
	 * 
	 * @param obj the object from which the json-string generate
	 * @return
	 */
	public static String fromArray(Object obj) {
		return fromArray(obj,"\"");
	}
	
	/**
	 * the obj must a array
	 * @param obj the object from which the json-string generate
	 * @param quote
	 * @return
	 */
	public static String fromArray(Object obj,String quote)  {
		if(!obj.getClass().isArray()){
			new Exception("invalid argument,a array is required").printStackTrace();
			return null;
		}
		StringBuffer buf = new StringBuffer();
		runFor(obj, buf, quote);
		if(!obj.getClass().getComponentType().isArray()){
			buf.deleteCharAt(buf.length() -1);
		}
		return buf.toString();
	}
	
	/**
	 * generate the array json
	 * @param obj must be a array
	 * @param buffer
	 * @param quote
	 */
	public static void runFor(Object obj,StringBuffer buffer,String quote)  {
		if(!obj.getClass().isArray()){
			new Exception("invalid argument,a array is required").printStackTrace();
			return;
		}
		if(obj.getClass().getComponentType().isArray()){
			Object[] objs = (Object[]) obj.getClass().cast(obj);
			buffer.append("[");
			for(int i = 0,j = objs.length;i < j;i ++){
				runFor(objs[i],buffer,quote);
			}
			buffer.deleteCharAt(buffer.length() -1);
			buffer.append("],");
		}else{
			fillOneDArrayToBuffer(buffer, obj,quote);
			buffer.append(",");
		}
	}
	
	/**
	 * generate array string to the buffer
	 * @param buffer
	 * @param obj
	 * @param quote
	 */
	public static void fillOneDArrayToBuffer(StringBuffer buffer,Object obj,String quote) {
		buffer.append("[");
		if(ArrayUtils.isPrimitiveArray(obj)){
				String className = obj.getClass().getName();
				String key = className.substring(className.length() -1);
				int index = "CBSIJFD".indexOf(key);
				switch(index){
				case 0:char[] chars = (char[])obj;
				for(char ch:chars){
					buffer.append(ch).append(",");
				}
					break;
				case 1:byte[] bytes = (byte[])obj;
				for(byte byt:bytes){
					buffer.append(byt).append(",");
				}
				break;
				case 2:short[] shorts = (short[])obj;
				for(short sht:shorts){
					buffer.append(sht).append(",");
				}
					break;
				case 3:int[] ints = (int[])obj;
				for(int in:ints){
					buffer.append(in).append(",");
				}
					break;
				case 4:long[] longs = (long[])obj;
				for(long lon:longs){
					buffer.append(lon).append(",");
				}
					break;
				case 5:float[] floats = (float[])obj;
				for(float floa:floats){
					buffer.append(floa).append(",");
				}
					break;
				case 6:double[] doubles = (double[])obj;
				for(double doub:doubles){
					buffer.append(doub).append(",");
				}
					break;
				}
			}else{
				Object[] objs = (Object[]) obj;
				for(Object object:objs){
					if(object instanceof String){
						object = quote + ((String)object).replaceAll("\\\"", "\\\\\"") + quote;
						buffer.append(object);
					}
					else
					fromObject(object, buffer, quote);
					buffer.append(",");
				}
			}
		buffer.deleteCharAt(buffer.length() -1);
		buffer.append("]");
	}
	
	public static void main(String[] args)  throws Exception {
		org.openjava.model.Contact contact = new org.openjava.model.Contact();
		contact.setAddress("234");
		contact.setTelephone("12323");
		contact.setZipcode("323300");
		org.openjava.model.People p = new org.openjava.model.People();
		p.setAge(22);
		p.setContact(contact);
		p.setDate(new Date());
		p.setName("LeiTing");
		p.setSex("male");
		p.setTest(new int[]{1,2,3});
		
		org.openjava.model.Contact contact2 = new org.openjava.model.Contact();
		contact2.setAddress("234");
		contact2.setTelephone("12323");
		contact2.setZipcode("323300");
		org.openjava.model.People p2 = new org.openjava.model.People();
		p2.setAge(22);
		p2.setContact(contact2);
		p2.setDate(new Date());
		p2.setName("LeiTing");
		p2.setSex("male");
		p2.setTest(new int[]{1,2,3});
		
		p.setFather(p2);
		long start = System.currentTimeMillis();
		for(int i = 0;i < 10000;i ++){
			JSONBuilder.fromObject(p);
		}
		long end = System.currentTimeMillis();
		System.out.println(end - start);
	}
}

